<template>
  <div class="blog-toc-container">
    <h2>目录</h2>
    <RightList :list="tocWithSelect" @select="handleSelect" />
  </div>
</template>
<script lang="ts" setup>
import RightList from './RightList.vue'
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import emitter from '@/utils/EventBus'

interface Props {
  toc: any[]
}

const props = defineProps<Props>()

const activeAnchor = ref('')

// 加一个 isSelect 属性
const tocWithSelect = computed(() => {
  const getToc = (toc: any[] = []): any[] => {
    return toc.map(t => ({
      ...t,
      isSelect: activeAnchor.value === t.anchor,
      children: getToc(t.children)
    }))
  }
  return getToc(props.toc)
})

// 根据 toc 得到对应的元素数组
const getDoms = computed(() => {
  const doms: any[] = []
  const addToDoms = (toc: any[]) => {
    for (const item of toc) {
      doms.push(document.getElementById(item.anchor))
      if (item.children && item.children.length) {
        addToDoms(item.children)
      }
    }
  }
  addToDoms(props.toc)
  return doms
})

onMounted(() => {
  emitter.on('mainScroll', setSelect)
})

onBeforeUnmount(() => {
  emitter.off('mainScroll', setSelect)
})

const handleSelect = (item: any) => {
  location.hash = item.anchor
}

const setSelect = () => {
  // 先清空
  activeAnchor.value = ''
  // 规定显示范围
  const range = 200
  for (const dom of getDoms.value) {
    if (!dom) continue
    const rect = dom.getBoundingClientRect()
    if (rect.top >= 0 && rect.top <= range) {
      // 在范围内
      activeAnchor.value = dom.id
    } else if (rect.top > range) {
      // 在范围下方
      return
    } else {
      activeAnchor.value = dom.id
    }
  }
}
</script>
<style lang="less" scoped>
.blog-toc-container {
  h2 {
    font-weight: bold;
    letter-spacing: 2px;
    font-size: 1em;
    margin: 0;
  }
}
</style>